package cn.com.bsfit.netty.handler;

import cn.com.bsfit.netty.config.base.BaseConfigurable;
import cn.com.bsfit.netty.config.constants.ErrorCodeEnums;
import cn.com.bsfit.netty.req.DefaultReqDataFormat;
import cn.com.bsfit.netty.req.ReqData2MapFacade;
import cn.com.bsfit.netty.req.ReqData2MapStrategy;
import cn.com.bsfit.netty.resp.BaseResponse;
import com.google.common.base.Stopwatch;
import cn.com.bsfit.netty.config.properties.BaseNettyServerProperties;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Map;

/**
 * 类名 AbstractRequestHandler
 * 描述 抽象请求处理器
 *
 * @author hedonglin
 * @version 1.0
 * @date 2019/9/29 10:59
 */
@Slf4j
@ChannelHandler.Sharable
public abstract class AbstractRequestHandler<T extends BaseNettyServerProperties> extends SimpleChannelInboundHandler<String> implements Serializable, BaseConfigurable {
    private static final long serialVersionUID = 6650695629220146041L;

    @Autowired
    private Map<String, ReqData2MapStrategy> reqData2MapStrategyMap;
    @Autowired
    private DefaultReqDataFormat jsonReqFormat;


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        ReqData2MapFacade reqData2MapFacade = new ReqData2MapFacade(reqData2MapStrategyMap, jsonReqFormat);
        BaseNettyServerProperties.JsonResponse jsonResponse = getNettyServerProperties().getJsonResponse();
        BaseNettyServerProperties.XmlResponse xmlResponse = getNettyServerProperties().getXmlResponse();

        // 计算耗时
        Stopwatch stopwatch = Stopwatch.createStarted();
        Map<String, Object> reqMap = null;
        Map<String, Object> resMap;
        boolean isContainsTop = false;
        boolean isContainsHead = false;
        boolean isContainsBody = false;
        String resStr = "";
        try {
            // 1、将请求数据转换为Map格式
            reqMap = reqData2MapFacade.reqDataToMap(msg);
            boolean isJson = reqData2MapFacade.isJson();
            boolean isXml = reqData2MapFacade.isXml();

            // 2、head和Body合并
            Map<String, Object> mergedReqMap = reqData2MapFacade.mergeHeadBody(reqMap);

            // 3、真正的业务逻辑处理
            resMap = reqHandler(mergedReqMap, reqData2MapFacade);

            // 4、包装真正业务返回的数据为统一返回格式
            if (isJson){
                isContainsTop = jsonResponse.isContainsTop();
                isContainsHead = jsonResponse.isContainsHead();
                isContainsBody = jsonResponse.isContainsBody();
            }else if (isXml){
                isContainsTop = xmlResponse.isContainsTop();
                isContainsHead = xmlResponse.isContainsHead();
                isContainsBody = xmlResponse.isContainsBody();
            }
            boolean notInTopField = reqData2MapFacade.isNotInTopField();
            if (notInTopField){
                resMap = BaseResponse.builder().error(BaseResponse.REQ_PARAM_ERR_CODE, "数据格式验证失败");
            }
            // 5、将统一返回格式数据转换为字符串返回结果
            resStr = reqData2MapFacade.resMapToStr(reqMap, resMap, isContainsTop, isContainsHead, isContainsBody);

            // 子类对结果的处理
            writeResponse(ctx, resStr,stopwatch);
        }catch (Exception e){
            e.printStackTrace();
            String errMsg = e.getMessage() != null ? e.getMessage() : ErrorCodeEnums.SERVER_INNER_ERROR.getErrCodeDesc();
            // 转换为字符串返回结果
            BaseResponse error = BaseResponse.builder().error(BaseResponse.REQ_PARAM_ERR_CODE, errMsg);
            resStr = reqData2MapFacade.resMapToStr(reqMap, error , xmlResponse.isContainsTop(), xmlResponse.isContainsHead(), xmlResponse.isContainsBody());
            // 子类对结果的处理
            writeResponse(ctx, resStr,stopwatch);
            log.error(errMsg);
        }
    }
    
    /**
     * 方法描述: 获取配置文件
     * @author hedonglin
     * @date 2019/9/27 16:04
     * @return {@link T} 配置文件泛型
     */
    public abstract T getNettyServerProperties();


    /**
     * 方法描述: 各自的请求处理
     * @param reqMap 请求参数
     * @param reqData2MapFacade 业务可能需要用到该类获取一些状态，注意：这里传递引用
     * @author hedonglin
     * @date 2019/9/25 15:33
     * @return {Map} 返回结果Map
     */
    public abstract Map<String, Object> reqHandler(Map<String, Object> reqMap, ReqData2MapFacade reqData2MapFacade) throws Exception;

    /**
     * 方法描述: 回写数据部分
     * @param ctx ChannelHandlerContext
     * @param resultMsg 返回数据
     * @param stopwatch 时间计量
     * @author hedonglin
     * @date 2019/9/27 15:10
     */
    protected abstract void writeResponse(ChannelHandlerContext ctx, String resultMsg, Stopwatch stopwatch);
}
